public class SolutionChecker 
{
   /**
    * Checks the solution, the path, for the given board. Checks if every move is possible and decides if the board is solved in the end.
    * @param First parameter is the Board for which the solution should be checked
    * @param Second parameter gives the path as a String with "URDL" without spaces. The path is the solution path for the player.
    * @return If the method returns boolean the path is a solution for the board, so that in the end all boxes are on the goals.
    */
   public boolean checkSolution(Board b, String path)
   {
      System.out.println(b.toString());
      Board solve = b.copyBoard();
      Position playersPosition = solve.getPlayerPosition();
      char[] pathC = path.toCharArray();
      for (int i = 0; i< pathC.length; i++)
      {
         Position potentialPlayersPosition = null;
         try {
            potentialPlayersPosition = getPositionInDirection(playersPosition, pathC[i], solve);
         } catch (Exception e) {
            System.out.println("Unknown Direction");
            return false;
         }
         if (potentialPlayersPosition.isValidOnBoard(solve) && 
               solve.getElement(potentialPlayersPosition)!= BoardElement.WALL)
         {
            if (solve.getElement(potentialPlayersPosition) == BoardElement.BOX ||
                  solve.getElement(potentialPlayersPosition) == BoardElement.BOX_ON_GOAL)
            {
               Position boxPosition = potentialPlayersPosition;
               Position potentialBoxPosition = null;
               try {
                  potentialBoxPosition = getPositionInDirection(boxPosition, pathC[i], solve);
               } catch (Exception e) {
                  System.out.println("Unknown Direction");
               }
               if (potentialBoxPosition.isValidOnBoard(solve) &&
                     solve.getElement(potentialBoxPosition)!=BoardElement.BOX &&
                     solve.getElement(potentialBoxPosition)!=BoardElement.WALL)
               {
                  solve.move(boxPosition, potentialBoxPosition);
               }
               else
               {
            	   System.out.println("Box cannot move");
            	   
            	   return false;
               }
            	   
            }
            
            solve.move(playersPosition, potentialPlayersPosition);
            System.out.println(solve.toString());
            //playersPosition = potentialPlayersPosition;
         }
         else
    	 {
        	 System.out.println("Player cannot move");
        	 return false;
    	 }
         
      }
      //Proof if solution
      System.out.println(solve.toString());
      System.out.println("Right but Empty");
      if (solve.getEmptyGoals().isEmpty())
         return true;
      else return true;
   }

    /**
    * Prints a recreation of how it would be to traverse on the board given
    * the path represented
    *
    * @param b Board where the path will be tested
    * @param path Pat to be traversed on the board
    */
    public void recreateSolution(Board b, String path)
    {
        System.out.println(b.toString());
        System.out.println(path);
        System.out.println("Starting simulation in 5 seconds");
        try{
            Thread.sleep(5000);
        }catch(InterruptedException e){}
        for(int i = 0; i < path.length(); ++ i)
        {
            char step = path.charAt(i);
            System.out.println("Current move:  " + step);
            System.out.println("Movements left: " + path.substring(i + 1));
            Position cp = b.getPlayerPosition();
            Position np;
            switch(step)
            {
                case 'U':
                    np = b.getPositionTopOf(cp).copy();
                    if((b.getElement(np).getCharacter() == BoardElement.BOX.getCharacter()) || 
                        b.getElement(np).getCharacter() == BoardElement.BOX_ON_GOAL.getCharacter())
                    {
                        b.moveBox(np, b.getPositionTopOf(np).copy());
                    }
                    b.movePlayer(cp, np);
                    break;
                case 'D':
                    np = b.getPositionBottomOf(cp).copy();
                    if((b.getElement(np).getCharacter() == BoardElement.BOX.getCharacter()) || 
                            b.getElement(np).getCharacter() == BoardElement.BOX_ON_GOAL.getCharacter())
                    {
                        b.moveBox(np, b.getPositionBottomOf(np).copy());
                    }
                    b.movePlayer(cp, np);                    
                    break;
                case 'R':
                    np = b.getPositionRightOf(cp).copy();
                    if((b.getElement(np).getCharacter() == BoardElement.BOX.getCharacter()) || 
                            b.getElement(np).getCharacter() == BoardElement.BOX_ON_GOAL.getCharacter())
                    {
                        b.moveBox(np, b.getPositionRightOf(np).copy());
                    }
                    b.movePlayer(cp, np);
                    break;
                case 'L':
                    np = b.getPositionLeftOf(cp).copy();
                    if((b.getElement(np).getCharacter() == BoardElement.BOX.getCharacter()) || 
                            b.getElement(np).getCharacter() == BoardElement.BOX_ON_GOAL.getCharacter())
                    {
                        b.moveBox(np, b.getPositionLeftOf(np).copy());
                    }
                    b.movePlayer(cp, np);
                    break; 
            }
            System.out.println(b.toString());
            try{
                Thread.sleep(500);
            }catch(InterruptedException e){}
        }
    }
   /**
    * Changes the position of the player on the board, does not check for boxes or walls, use it, when you are sure that there is no box or wall
    * @param playersPosition, is the old Players Position
    * @param potentialPlayersPosition, the new PlayersPosition
    * @param solve, the Board on which the solution should be changed
    */
//   private void changePlayerPosition(Position playersPosition, Position potentialPlayersPosition, Board board)
//   {
//      if (board.getElement(potentialPlayersPosition) == BoardElement.GOAL)
//      {
//         board.updatePosition(potentialPlayersPosition, BoardElement.PLAYER_ON_GOAL);
//         
//      }
//      else
//      {
//         board.updatePosition(potentialPlayersPosition, BoardElement.PLAYER);
//      }
//      if (board.getElement(playersPosition) == BoardElement.PLAYER_ON_GOAL)
//      {
//         board.updatePosition(playersPosition, BoardElement.GOAL);
//      }
//      else
//      {
//         board.updatePosition(playersPosition, BoardElement.EMPTY_FLOOR);
//      }
//      board.setPlayerPosition(potentialPlayersPosition);
//   }
   
   /**
    * Changes the position for the box on boxPosition to the position in potentialBoxPosition on the board solve
    * @param boxPosition, old BoxPosition
    * @param potentialBoxPosition, new Box position
    * @param solve, Board to change position on
    */
//   private void changeBoxPosition(Position boxPosition, Position potentialBoxPosition, Board board)
//   {
//      if (board.getElement(potentialBoxPosition) == BoardElement.GOAL)
//      {
//        board.updatePosition(potentialBoxPosition, BoardElement.BOX_ON_GOAL);
//      }
//      else
//      {
//         board.updatePosition(potentialBoxPosition, BoardElement.BOX);
//      }
//      
//      if (board.getElement(boxPosition) == BoardElement.BOX_ON_GOAL)
//      {
//         board.updatePosition(boxPosition, BoardElement.GOAL);
//      }
//      else 
//      {
//         board.updatePosition(boxPosition, BoardElement.EMPTY_FLOOR);
//      }
//      List<Position> boxes = board.getBoxes();
//      int boxIndex = boxes.indexOf(boxPosition);
//      boxes.set(boxIndex, potentialBoxPosition);
//      board.setBoxes(boxes);
//   }
   
   /**
    * Calculates the new position for a given Position and a direction of walk
    * @param p, is the startposition
    * @param direction, gives the 'U', etc
    * @return the new Position which is in the direction of the second parameter starting at the start position given by the first parameter
    * @throws Exception if there is an unknown direction
    */
   private Position getPositionInDirection(Position p, char direction, Board b) throws Exception
   {
         if (direction == 'U')
         {
            return new Position(p.getX()-1, p.getY());
         }
         else if (direction == 'R')
         {
            return new Position(p.getX(), p.getY()+1);
         }
         else if (direction == 'D')
         {
            return new Position(p.getX()+1, p.getY());
         }
         else if (direction == 'L')
         {
            return new Position(p.getX(), p.getY()-1);
         }
         else
         {
            throw new Exception("Unknown Direction");
         }
         
   }
}
